package com.efamily.ewallet.client.expense.widget;

import java.util.Date;
import java.util.List;

import com.efamily.ewallet.client.account.bean.AccountBean;
import com.efamily.ewallet.client.common.DefaultAsyncCallback;
import com.efamily.ewallet.client.common.CustomEvents;
import com.efamily.ewallet.client.common.CustomEventType;
import com.efamily.ewallet.client.expense.bean.ExpenseBean;
import com.efamily.ewallet.client.expense.bean.ExpenseCategoryBean;
import com.efamily.ewallet.client.expense.bean.ExpenseTypeBean;
import com.efamily.ewallet.client.expense.service.ExpenseServiceAsync;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelLookup;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.DateField;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.FormPanel.LabelAlign;
import com.extjs.gxt.ui.client.widget.layout.ColumnData;
import com.extjs.gxt.ui.client.widget.layout.ColumnLayout;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FormData;
import com.extjs.gxt.ui.client.widget.layout.FormLayout;
import com.google.gwt.i18n.client.DateTimeFormat;

public class AddEditExpenseWindow extends Window {
	private final ExpenseServiceAsync expenseService = ExpenseServiceAsync.instance;
	private AddEditForm form = new AddEditForm();
	private ExpenseBean expenseBean = new ExpenseBean();
	private AccountBean accountBean = new AccountBean();

	public AddEditExpenseWindow() {
		setSize(500, 400);
		setPlain(true);
		setResizable(false);
		setClosable(true);
		setModal(true);
		setBlinkModal(true);
		setHeading("Add/Edit Expense");
		setLayout(new FitLayout());
		add(form);
	}

	public void showAddWindow(AccountBean accountBean) {
		this.accountBean = accountBean;
		expenseBean = new ExpenseBean();
		show();
	}

	public void showEditWindow(AccountBean accountBean, ExpenseBean expense) {
		this.accountBean = accountBean;
		expenseBean = expense;
		show();
	}

	private class AddEditForm extends Composite {
//TODO create common method for reseting form
		private TextField<String> nameFld = new TextField<String>();
		private ComboBox<BeanModel> categoryCmb = new ComboBox<BeanModel>();
		private ComboBox<ExpenseTypeBean> typeCmb = new ComboBox<ExpenseTypeBean>();
		private DateField expenseDateFld = new DateField();
		private NumberField costFld = new NumberField();
		private TextArea descriptionArea = new TextArea();
		private Button saveBtn = new Button("Save");
		private FormPanel formPanel = new FormPanel();

		public AddEditForm() {
			buildForm();
			initComponent(formPanel);
			this.addListener(Events.Attach, new Listener<BaseEvent>() {
				public void handleEvent(BaseEvent be) {
					loadExpenseCategories();
					if (expenseBean.getId() == -1) {
						nameFld.reset();
						costFld.setValue(0);
						descriptionArea.reset();
						expenseDateFld.setValue(new Date());
					} else {
						nameFld.setValue(expenseBean.getName());
						costFld.setValue(expenseBean.getCost());
						descriptionArea.setValue(expenseBean.getDescription());
						expenseDateFld.setValue(expenseBean
								.getExpenseDate());
					}
				}
			});
		}

		private void buildForm() {
			FormData formData = new FormData("95%");
			// Left column
			LayoutContainer left = new LayoutContainer();
			left.setStyleAttribute("paddingRight", "10px");
			FormLayout layout = new FormLayout();
			layout.setLabelAlign(LabelAlign.TOP);
			left.setLayout(layout);
			nameFld.setFieldLabel("Expense*");
			nameFld.setEmptyText("Expense name");
			nameFld.setAllowBlank(false);
			left.add(nameFld, formData);

			categoryCmb.setStore(new ListStore<BeanModel>());
			categoryCmb.setFieldLabel("Category");
			categoryCmb.setEmptyText("Select category");
			categoryCmb.setTriggerAction(TriggerAction.ALL);
			categoryCmb.setTypeAhead(true);
			categoryCmb.setFireChangeEventOnSetValue(true);
			categoryCmb.setDisplayField("name");
			categoryCmb.setForceSelection(true);
			categoryCmb.setMonitorTab(true);
			categoryCmb
					.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {
						@Override
						public void selectionChanged(
								SelectionChangedEvent<BeanModel> se) {
							try {
								typeCmb.getStore().removeAll();
								typeCmb.setValue(null);
								if (se.getSelectedItem() != null) {
									ExpenseCategoryBean category = se
											.getSelectedItem().getBean();
									if (category != null && category.getTypes()!= null) {
										typeCmb.getStore().add(
												category.getTypes());
										if (expenseBean.getId() != -1) {
											typeCmb.setValue(expenseBean
													.getType());
										}
									}
								}
							} catch (Exception ex) {
								MessageBox.alert("Operation failed", ex
										.getMessage(), null);
								ex.printStackTrace();
							}
						}
					});
			left.add(categoryCmb, formData);

			// Center column

			LayoutContainer center = new LayoutContainer();
			center.setStyleAttribute("paddingRight", "10px");
			center.setStyleAttribute("paddingLeft", "10px");
			layout = new FormLayout();
			layout.setLabelAlign(LabelAlign.TOP);
			center.setLayout(layout);
			costFld.setFieldLabel("Cost*");
			costFld.setAllowBlank(false);
			costFld.setSelectOnFocus(true);
			center.add(costFld, formData);
			typeCmb.setStore(new ListStore<ExpenseTypeBean>());
			typeCmb.setFieldLabel("Type");
			typeCmb.setEmptyText("Select type");
			typeCmb.setTypeAhead(true);
			typeCmb.setTriggerAction(TriggerAction.ALL);
			typeCmb.setDisplayField("name");
			typeCmb.setForceSelection(true);
			center.add(typeCmb, formData);

			// Right column

			LayoutContainer right = new LayoutContainer();
			right.setStyleAttribute("paddingLeft", "10px");
			layout = new FormLayout();
			layout.setLabelAlign(LabelAlign.TOP);
			right.setLayout(layout);
			expenseDateFld.setFieldLabel("Date*");
			expenseDateFld.setAllowBlank(false);
			expenseDateFld.getPropertyEditor().setFormat(
					DateTimeFormat.getFormat("EEE, d MMM, ''yy "));
			right.add(expenseDateFld, new FormData("90%"));

			// Main panel

			LayoutContainer main = new LayoutContainer();
			main.setLayout(new ColumnLayout());
			main.add(left, new ColumnData(.33));
			main.add(center, new ColumnData(.33));
			main.add(right, new ColumnData(.33));

			// Form panel
			formPanel.setHeaderVisible(false);
			formPanel.setLabelAlign(LabelAlign.TOP);
			formPanel.add(main);
			descriptionArea.setFieldLabel("Description");
			descriptionArea.setEmptyText("You can type description here...");
			descriptionArea.setHeight(200);
			formPanel.add(descriptionArea, new FormData("100%"));
			saveBtn.addSelectionListener(new SelectionListener<ButtonEvent>() {
				@Override
				public void componentSelected(ButtonEvent ce) {
					try {
						addEditExpense();
					} catch (Exception ex) {
						MessageBox.alert("Operation failed", ex.getMessage(),
								null);
						ex.printStackTrace();
					}
				}
			});
			formPanel.addButton(saveBtn);
		}
		
		private void loadExpenseCategories(){
			expenseService.getCategories(accountBean, new DefaultAsyncCallback<List<ExpenseCategoryBean>>(){
				@Override
				public void onSuccess(List<ExpenseCategoryBean> expenseCategories) {
					categoryCmb.getStore().removeAll();
					categoryCmb.getStore().add(BeanModelLookup.get()
							.getFactory(
									ExpenseCategoryBean.class)
							.createModel(
									expenseCategories));
					if (expenseBean.getId() == -1) {
						categoryCmb.setValue(null);
					} else {
						categoryCmb.setValue(BeanModelLookup.get()
								.getFactory(
										ExpenseCategoryBean.class)
								.createModel(
										expenseBean.getCategory()));
					}

				}
			});
		}

		private void addEditExpense() {
			if (nameFld.isValid() && costFld.isValid()
					&& expenseDateFld.isValid()) {

				expenseBean.setName(nameFld.getValue());
				expenseBean.setCost(costFld.getValue().doubleValue());
				expenseBean.setDescription(descriptionArea.getValue());
				expenseBean.setExpenseDate(expenseDateFld.getValue());
				ExpenseTypeBean type = null;
				if (typeCmb.getValue() != null) {
					type = typeCmb.getValue();
				} else if (!typeCmb.getRawValue().isEmpty()) {
					type = new ExpenseTypeBean(typeCmb.getRawValue());
				}
				expenseBean.setType(type);
				ExpenseCategoryBean category = null;
				if (categoryCmb.getValue() != null) {
					category = categoryCmb.getValue().getBean();
				} else if (!categoryCmb.getRawValue().isEmpty()) {
					category = new ExpenseCategoryBean(categoryCmb
							.getRawValue());
				}
				expenseBean.setCategory(category);

				expenseService.addEditExpense(accountBean, expenseBean,
						new DefaultAsyncCallback<Boolean>() {
							@Override
							public void onSuccess(Boolean isDone) {
								if (isDone) {
									Dispatcher.get().fireEvent(CustomEvents.ADD_EXPENSE.getEventType());
									AddEditExpenseWindow.this.hide();
								} else {
									MessageBox
											.alert(
													"Operation failed",
													"Some exception was thrown. Try again or ask administrator.",
													null);
								}
							}
						});

			}
		}
	}

}